#include "event_async.h"
#include "event_loop.h"

namespace rr {
namespace nio {


EventAsync::EventAsync(EventLoop* loop)
: loop_(loop)
{

}

EventAsync::~EventAsync()
{

}

int32_t EventAsync::Start()
{
    uv_async_init(loop_->GetLoop(), &uv_async_, EventAsync::OnAsyncCb);
    uv_async_.data = this;

    EventRecord::Sptr record = std::make_shared<EventRecord>(EventRecord::ASYNC, &uv_async_);
    loop_->GetEventRecorder()->AddRecord(record);
    return 0;
}

// must be by call on loop thread
void EventAsync::Close(const AsyncCloseCallback& cb)
{
    close_cb_ = cb;
    uv_close((uv_handle_t*)&uv_async_, EventAsync::OnCloseCb);
    return;
}


int32_t EventAsync::submit(const PendingCallback &cb)
{
    {
        std::lock_guard<std::mutex> lock(mutex_);
        pending_cbs.push_back(cb);
    }

    uv_async_send(&uv_async_);

    return 0;    
}

void EventAsync::OnAsyncCb(uv_async_t* handle)
{
    auto async = static_cast<EventAsync*>(handle->data);
	if (async){
		async->DoCallback();
    }

    return;
}

void EventAsync::DoCallback()
{
    PendingCallbackList cbs;
    {
        std::lock_guard<std::mutex> lock(mutex_);
        cbs.swap(pending_cbs);
    }

    while (!cbs.empty())
    {
        auto &func = cbs.front();
        func();
		cbs.pop_front();
    }

    return;
}

void EventAsync::OnCloseCb(uv_handle_t* handle)
{
    auto async = static_cast<EventAsync*>(handle->data);
    async->loop_->GetEventRecorder()->RemoveRecord(handle);
    if (async) {
        async->DoClose();
    }
    
}

void EventAsync::DoClose()
{
    if (close_cb_) {
        close_cb_();
    }
}

} //namespace 
} //namespace 